package com.yxx.service.Impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.SaSessionCustomUtil;
import cn.dev33.satoken.spring.sso.SaSsoBeanInject;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxx.constant.CommonConstant;
import com.yxx.entity.Role;
import com.yxx.entity.UserRole;
import com.yxx.entityModel.vo.Result.PageResult;
import com.yxx.entityModel.vo.query.RoleQuery;
import com.yxx.entityModel.vo.request.RoleRequest;
import com.yxx.entityModel.vo.response.RoleResponse;
import com.yxx.entityModel.vo.response.RoleStatusRequest;
import com.yxx.mapper.RoleMapper;
import com.yxx.mapper.RoleMenuMapper;
import com.yxx.mapper.UserRoleMapper;
import com.yxx.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.swing.text.html.Option;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author yuxiangxun
 * @date 2025/2/5
 * @apiNote
 */
@Service
@Slf4j
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    /**
     * 查看后台角色列表
     * @param roleQuery
     * @return
     */
    @Override
    public PageResult<RoleResponse> roleList(RoleQuery roleQuery) {
        // 查询角色数量
        Long count = roleMapper.selectBackRoleCount(roleQuery);
        // 如果角色数量为0，则new一个分页结果对象并返回
        if(count == 0){
            return new PageResult<>();
        }
        // 如果角色数量不为0，则分页查询后台角色列表
        List<RoleResponse> roleResponsesList = roleMapper.selectBackRoleList(roleQuery);
        return new PageResult<>(roleResponsesList,count);
    }

    /**
     * 添加角色
     * @param roleRequest
     */
    @Override
    public void addRole(RoleRequest roleRequest) {
        // 查看请求中的角色名称对应的角色信息是否在数据库中存在
        Role existRole = roleMapper.selectOne(new LambdaQueryWrapper<Role>()
                .select(Role::getId).eq(Role::getRoleName, roleRequest.getRoleName()));
        // 断言，如果存在，显示“角色名已存在”，无法执行下面的逻辑
        Assert.isNull(existRole,roleRequest.getRoleName()+"这个角色名已存在");
        // 添加角色 创建新的角色对象
        Role newRole = Role.builder()
                .roleName(roleRequest.getRoleName())
                .roleDesc(roleRequest.getRoleDesc())
                .isDisable(roleRequest.getIsDisable())
                .build();
        // 插入到数据库
        baseMapper.insert(newRole);
        // 添加角色表单权限
        roleMenuMapper.insertRoleMenu(newRole.getId(),roleRequest.getMenuIdList());
    }

    @Override
    public void deleteRole(List<String> roleIdList) {
        // “管理员” 这个角色永远不允许被删除，写个断言如果包含管理员这个角色，则抛出异常，不允许删除管理员角色，且不执行下面的逻辑
        Assert.isFalse(roleIdList.contains(CommonConstant.ADMIN),"管理员角色不允许被删除");
        // 删除角色前，先判断该角色是否已经被分配，如果有和user关联，则不允许删除，抛出异常，不允许删除有用户关联的角色（角色已分配），且不执行下面的逻辑
        Long count = userRoleMapper.selectCount(new LambdaQueryWrapper<UserRole>()
                .in(UserRole::getRoleId, roleIdList));
        Assert.isFalse(count > 0,"角色已分配，不允许删除");
        // 批量删除角色
        roleMapper.deleteBatchIds(roleIdList);
        // 批量删除角色关联的菜单权限，删除角色菜单中间表中相关数据即可
        roleMenuMapper.deleteRoleMenu(roleIdList);
        // 删除Redis缓存中的菜单权限
        roleIdList.forEach(roleId -> {
            SaSession sessionById = SaSessionCustomUtil.getSessionById("role-" + roleId, false);
            Optional.ofNullable(sessionById).ifPresent(saSession -> saSession.delete("Permission_List"));
        });
    }

    /**
     * 修改角色
     * @param roleRequest
     */
    @Override
    public void updateRole(RoleRequest roleRequest) {
        // 请求中角色id为管理员id或者角色状态设置为禁用状态，断言，抛出异常，当前角色不允许被修改，且不执行下面的逻辑
        Assert.isTrue(roleRequest.getId().equals(CommonConstant.ADMIN) || roleRequest.getIsDisable().equals(CommonConstant.FALSE),"当前角色不允许被修改");
        // 角色名是否存在(前端请求过来的新角色名与数据库中的角色名进行比较)，如果存在则角色重复，断言，抛出异常“角色名已存在”，且不执行下面的逻辑
        Role existRole = roleMapper.selectOne(new LambdaQueryWrapper<Role>()
                .select(Role::getId).eq(Role::getRoleName, roleRequest.getRoleName()));
        // 如果没有出现角色名重复 且 角色id与前端请求过来的角色id相等，则通过断言，否则不通过断言，抛出异常“角色名已存在”，且不执行下面的逻辑
        Assert.isFalse(Objects.nonNull(existRole) && !existRole.getId().equals(roleRequest.getId()),roleRequest.getRoleName()+"这个角色名已存在");
        // 创建新的角色对象，并更新数据库
        // 不推荐使用BeanCopyUtils.copyBean(roleRequest, Role.class);的原因个人角色里面有一个菜单列表属性，Role类没有这个属性，字段不匹配可能会导致不必要的错误
        Role newRole = Role.builder()
                .id(roleRequest.getId())
                .roleName(roleRequest.getRoleName())
                .roleDesc(roleRequest.getRoleDesc())
                .isDisable(roleRequest.getIsDisable())
                .build();
        roleMapper.updateById(newRole);
        // 先删除角色关联的菜单权限，再添加角色关联的菜单权限 （因为这里时修改操作，对应角色的权限可能被修改，先删除现有权限再添加修改后的权限）
        roleMenuMapper.deleteRoleMenuByRoleId(roleRequest.getId());
        roleMenuMapper.insertRoleMenu(newRole.getId(),roleRequest.getMenuIdList());
        // 还有删除 Redis 缓存中的权限
        SaSession sessionById = SaSessionCustomUtil.getSessionById("role-" + roleRequest.getId(), false);
        Optional.ofNullable(sessionById).ifPresent(saSession -> saSession.delete("Permission_List"));

    }

    /**
     * 修改角色状态
     * @param roleStatus
     */
    @Override
    public void updateRoleStatus(RoleStatusRequest roleStatus) {
        // 断言，如果角色id等于管理员id，则抛出异常，不允许禁用管理员角色，且不执行下面的逻辑
        Assert.isFalse(roleStatus.getId().equals(CommonConstant.ADMIN), "不允许禁用管理员角色");
        // 更新角色状态 创建新的角色对象，并更新数据库
        Role newRole = Role.builder()
                .id(roleStatus.getId())
                .isDisable(roleStatus.getIsDisable())
                .build();
        roleMapper.updateById(newRole);
    }

    /**
     * 查看角色的菜单权限
     * @param roleId
     * @return
     */
    @Override
    public List<Integer> listRoleMenuTree(String roleId) {
        return roleMenuMapper.selectMenuByRoleId(roleId);
    }
}
